package cn.cl.lock;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * https://www.jianshu.com/p/599c2bbd5f4e
 */
public class ExcutorZkLock extends AbstractZkLock {
    private static final Logger log= LoggerFactory.getLogger(ExcutorZkLock.class);
    @Override
    void waitLock() throws Exception {
        log.info("等待锁");
        Stat stat = zkClient.checkExists().forPath(WAIT_PATH);
        if(stat!=null){
            try {
                System.out.println(Thread.currentThread().getName()
                        +"等待节点:"+WAIT_PATH+"解锁");
                CountDownLatch latch = new CountDownLatch(1);
                PathChildrenCache cache = new PathChildrenCache(zkClient,PATH,true);
                PathChildrenCacheListener listener= new PathChildrenCacheListener() {
                    @Override
                    public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                        PathChildrenCacheEvent.Type type = event.getType();
                        if (type.equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
                            String path= event.getData().getPath();
                            if (WAIT_PATH.equals(path)) {
                                System.out.println(WAIT_PATH+"锁被删除了");
                                latch.countDown();
                            }
                        }
                    }
                };
                cache.start();
                cache.getListenable().addListener(listener);
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    boolean tryLock() throws Exception {
        log.info("尝试获取锁");
        //第一次进入
        if (CURRENTLOCK == null) {
            zkClient = getZkClient();
            //生成临时顺序节点
            CURRENTLOCK = zkClient.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(PATH+"/test");
            System.out.println("CURRENTLOCK:"+CURRENTLOCK);
        }

        //获取父节点下的所有临时顺序节点
        List<String> children = zkClient.getChildren().forPath(PATH);
        Collections.sort(children);
        for (String child : children) {
            System.out.println(child);
        }
        //判断当前节点是否是最小节点
        if (CURRENTLOCK.equals(PATH + "/" + children.get(0))) {
            System.out.println("当前节点是最小节点");
            return true;
        } else {
            //获取前一个节点
            int index = Collections.binarySearch(children, CURRENTLOCK.substring(PATH.length() + 1));
            WAIT_PATH=PATH+"/"+children.get(index-1);
        }
        return false;
    }


    public static void main(String[] args) throws Exception {
        ExcutorZkLock lock = new ExcutorZkLock();
        lock.tryLock();
    }

}
